package comm;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import structures.City;
import structures.CityByCoordinates;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.URL;

/**
 * Created with IntelliJ IDEA.
 * User: dna
 * Date: 27.04.13
 * Time: 16:28
 */
public class OutputTask {

    private EZConnection conn;

    public OutputTask(URL url) {
        conn = new EZConnection(url);
    }

    /**
     * Create a new XML document.
     * @return DOM Document
     * @throws ParserConfigurationException
     */
    private Document generateXML() throws ParserConfigurationException {
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        return docBuilder.newDocument();
    }

    /**
     * Add a new function to a XML DOM Document.
     * @param doc DOM Document
     * @return the new function element
     * @throws ParserConfigurationException
     */
    private Element addFunctionToXML(Document doc) throws ParserConfigurationException {
        Element rootElement = doc.createElement("Weather");
        doc.appendChild(rootElement);

        // Function element
        Element function = doc.createElement("Function");
        rootElement.appendChild(function);

        return function;
    }

    /**
     * Transfer current DOM Document to the service.
     * @param doc DOM Document to send
     * @throws TransformerException
     * @throws IOException
     */
    private void sendXML(Document doc) throws TransformerException, IOException {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);

        // open a new connection
        conn.open();
        conn.setMethod(EZConnection.Method.POST);
        conn.setProperty("Content-Type", "text/xml");

        // send data
        BufferedWriter bufferedWriter = conn.getOutputWriter();
        transformer.transform(source, new StreamResult(bufferedWriter));

        int responseCode = conn.getResponseCode();

        if (responseCode != 200)
            throw new IOException("Response code: " + responseCode);

        // close connection
        conn.close();
    }

    /**
     * Generate a new function request for the server with a place name.
     * @param cityName name of the city
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws TransformerException
     */
    public void addCityByName(String cityName) throws IOException, ParserConfigurationException, TransformerException {
        /*
        <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <Weather>
            <Function>
                <Name>setCityByName</Name>
                <Value>
                    <Place>MyCity</Place>
                </Value>
            </Function>
        </Weather>
        */

        // root elements
        Document doc = generateXML();

        // Function element
        Element function = addFunctionToXML(doc);

        // Name element
        Element name = doc.createElement("Name");
        name.appendChild(doc.createTextNode("setCityByName"));
        function.appendChild(name);

        // Value element
        Element value = doc.createElement("Value");
        function.appendChild(value);

        // Place element
        Element place = doc.createElement("Place");
        place.appendChild(doc.createTextNode(cityName));
        value.appendChild(place);

        sendXML(doc);
    }

    /**
     * Generate a new function request for the server with a ip.
     * @param cityIp a valid IP
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws TransformerException
     */
    public void addCityByIp(String cityIp) throws IOException, ParserConfigurationException, TransformerException {
        /*
        <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <Weather>
            <Function>
                <Name>setCityByName</Name>
                <Value>
                    <Ip>MyCityIp</Ip>
                </Value>
            </Function>
        </Weather>
        */

        // root elements
        Document doc = generateXML();

        // Function element
        Element function = addFunctionToXML(doc);

        // Name element
        Element name = doc.createElement("Name");
        name.appendChild(doc.createTextNode("setCityByIp"));
        function.appendChild(name);

        // Value element
        Element value = doc.createElement("Value");
        function.appendChild(value);

        // Ip element
        Element ip = doc.createElement("Ip");
        ip.appendChild(doc.createTextNode(cityIp));
        value.appendChild(ip);

        sendXML(doc);
    }

    /**
     * Generate a new function request for the server with place coordinates.
     * @param cityLatitude latitude of the place
     * @param cityLongitude longitude of the place
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws TransformerException
     */
    public void addCityByCoord(String cityLatitude, String cityLongitude) throws IOException, ParserConfigurationException, TransformerException {
        /*
        <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <Weather>
            <Function>
                <Name>setCityByCoordinates</Name>
                <Value>
                    <Latitude>Latitude</Latitude>
                    <Longitude>Longitude</Longitude>
                </Value>
            </Function>
        </Weather>
        */

        // root elements
        Document doc = generateXML();

        // Function element
        Element function = addFunctionToXML(doc);

        // Name element
        Element name = doc.createElement("Name");
        name.appendChild(doc.createTextNode("setCityByCoordinates"));
        function.appendChild(name);

        // Value element
        Element value = doc.createElement("Value");
        function.appendChild(value);

        // Latitude element
        Element latitude = doc.createElement("Latitude");
        latitude.appendChild(doc.createTextNode(cityLatitude));
        value.appendChild(latitude);

        // Latitude element
        Element longitude = doc.createElement("Longitude");
        longitude.appendChild(doc.createTextNode(cityLongitude));
        value.appendChild(longitude);

        sendXML(doc);
    }

    /**
     * Generate a new function request for the server with a place to be removed.
     * @param city the local city
     * @throws ParserConfigurationException
     * @throws TransformerException
     * @throws IOException
     */
    public void removeCity(City city) throws ParserConfigurationException, TransformerException, IOException {
        // root elements
        Document doc = generateXML();

        // Function element
        Element function = addFunctionToXML(doc);

        // Name element
        Element name = doc.createElement("Name");
        name.appendChild(doc.createTextNode("removeCityBy"+city.getByWhat()));
        function.appendChild(name);

        // Value element
        Element value = doc.createElement("Value");
        function.appendChild(value);

        if (city.getByWhat().equals("Name")){
            // Place element
            Element place = doc.createElement("Place");
            place.appendChild(doc.createTextNode(city.getName()));
            value.appendChild(place);
        } else if (city.getByWhat().equals("Ip")){
            // Ip element
            Element ip = doc.createElement("Ip");
            ip.appendChild(doc.createTextNode(city.getName()));
            value.appendChild(ip);
        } else if (city.getByWhat().equals("Coordinates")){
            CityByCoordinates temp = (CityByCoordinates)city;

            // Latitude element
            Element latitude = doc.createElement("Latitude");
            latitude.appendChild(doc.createTextNode(temp.getLatitude()));
            value.appendChild(latitude);

            // Latitude element
            Element longitude = doc.createElement("Longitude");
            longitude.appendChild(doc.createTextNode(temp.getLongitude()));
            value.appendChild(longitude);
        }

        sendXML(doc);
    }
}
